import { Application } from '../Application';
import { FrontendSession } from '../session/FrontendSession';
import { logger } from '../util/logger';
import { RpcMsg, RpcMsgId, SvrInfo } from '../util/defines';
import { TcpSocket } from '../tcp/TcpSocket';

/**
 * RpcSocket封装
 */
export abstract class RpcSocket {

    app: Application;
    socket: TcpSocket;
    remoteSvr: SvrInfo;

    constructor(app: Application, remoteSvr: SvrInfo) {
        this.app = app;
        this.remoteSvr = remoteSvr;
    }

    /**
     * 注册完成
     * @param socket 
     */
    protected onReg(socket: TcpSocket) {
        if (this.app.rpcService.svrs[this.remoteSvr.id]) {
            this.close();
            return false;
        }
        this.socket = socket;
        socket.on(this.onData.bind(this), this.onClose.bind(this));
        this.app.rpcService.svrs[this.remoteSvr.id] = this;
        logger.info(`${this.remoteSvr.id}注册完成`, RpcSocket, this.onReg);
        return true;
    }
    /**
     * 发送Rpc通信消息
     * @param msgId 
     * @param msg 
     */
    send<MsgId extends RpcMsgId>(msgId: RpcMsgId, msg?: RpcMsg<MsgId>) {
        this.socket.send({ msgId, msg });
    }

    /**
     * 关闭连接
     * @param isRemoved 
     */
    close() {
        this.socket.close();
        delete this.app.rpcService.svrs[this.remoteSvr.id];
    }

    private async onData(data: { msgId: RpcMsgId, msg: RpcMsg }) {
        let { msgId, msg } = data;
        switch (msgId) {
            case RpcMsgId.rpcCall:
                let call = msg as RpcMsg<typeof msgId>;
                let res = await this.app.rpcService.callRpcFunc(call.handler, call.func, call.args);
                !call.notify && this.send(RpcMsgId.rpcCallRes, { id: call.id, res });
                return;

            case RpcMsgId.rpcCallRes:
                let callRes = msg as RpcMsg<typeof msgId>;
                this.app.rpcService.onRpcCallRes(callRes.id, callRes.res);
                return;

            case RpcMsgId.syncSetting:
                let sync = msg as RpcMsg<typeof msgId>;
                let syncSess = this.app.getClient(sync.uid);
                if (syncSess) {
                    syncSess.set(sync.setting);
                    sync.deleteKeys && syncSess.delete(...sync.deleteKeys);
                }
                return;

            case RpcMsgId.msgSend:
                let send = msg as RpcMsg<typeof msgId>;

                let sessArr: FrontendSession[] = [];
                if (send.uid) {
                    let sess = this.app.getClient(send.uid);
                    sess && sessArr.push(sess);
                }
                if (send.uids) {
                    for (let uid of send.uids) {
                        let sess = this.app.getClient(uid);
                        sess && sessArr.push(sess);
                    }
                }

                for (let sess of sessArr) {
                    send.data && sess.socket.send(send.data as Buffer);
                    if (send.datas) {
                        for (let data of send.datas) {
                            sess.socket.send(data as Buffer);
                        }
                    }
                }
                return;

            case RpcMsgId.msgHandler:
                if (!this.app.backendSvr) return logger.error("后端消息错误地转发给了前端服务器", this, this.onData);
                this.app.backendSvr.handleMsg(msg as RpcMsg<typeof msgId>);
                return;
        }
        this.onMsg(data);
    }

    protected abstract onMsg(data: { msgId: RpcMsgId, msg: RpcMsg }): void;
    protected abstract onClose(err?: Error): void;

}